home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / uucp-104.lha / uucp-1.04 / tstuu.c < prev    next >
C/C++ Source or Header  |  1993-02-13  |  33KB  |  1,589 lines

  1. /* tstuu.c
  2.    Test the uucp package on a UNIX system.
  3.  
  4.    Copyright (C) 1991, 1992 Ian Lance Taylor
  5.  
  6.    This file is part of the Taylor UUCP package.
  7.  
  8.    This program is free software; you can redistribute it and/or
  9.    modify it under the terms of the GNU General Public License as
  10.    published by the Free Software Foundation; either version 2 of the
  11.    License, or (at your option) any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful, but
  14.    WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.    General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22.    The author of the program may be contacted at ian@airs.com or
  23.    c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
  24.    */
  25.  
  26. #include "uucp.h"
  27.  
  28. #if USE_RCS_ID
  29. const char tstuu_rcsid[] = "$Id: tstuu.c,v 1.74 1993/01/26 06:02:11 ian Rel $";
  30. #endif
  31.  
  32. #include "sysdep.h"
  33. #include "system.h"
  34. #include "getopt.h"
  35.  
  36. #include <stdio.h>
  37. #include <ctype.h>
  38. #include <errno.h>
  39.  
  40. #if HAVE_SYS_TIMES_H
  41. #include <sys/times.h>
  42. #endif
  43.  
  44. #if HAVE_SYS_IOCTL_H
  45. #include <sys/ioctl.h>
  46. #endif
  47.  
  48. #if HAVE_SELECT
  49. #include <sys/time.h>
  50. #if HAVE_SYS_SELECT_H
  51. #include <sys/select.h>
  52. #endif
  53. #endif
  54.  
  55. #if HAVE_POLL
  56. #if HAVE_STROPTS_H
  57. #include <stropts.h>
  58. #endif
  59. #if HAVE_POLL_H
  60. #include <poll.h>
  61. #endif
  62. #endif
  63.  
  64. #if HAVE_FCNTL_H
  65. #include <fcntl.h>
  66. #else
  67. #if HAVE_SYS_FILE_H
  68. #include <sys/file.h>
  69. #endif
  70. #endif
  71.  
  72. #ifndef O_RDONLY
  73. #define O_RDONLY 0
  74. #define O_WRONLY 1
  75. #define O_RDWR 2
  76. #endif
  77.  
  78. #if HAVE_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_SELECT)
  79. #include <time.h>
  80. #endif
  81.  
  82. #if HAVE_SYS_WAIT_H
  83. #include <sys/wait.h>
  84. #endif
  85.  
  86. #if HAVE_UNION_WAIT
  87. typedef union wait wait_status;
  88. #else
  89. typedef int wait_status;
  90. #endif
  91.  
  92. #if HAVE_STREAMS_PTYS
  93. #include <termio.h>
  94. extern char *ptsname ();
  95. #endif
  96.  
  97. /* Get definitions for both O_NONBLOCK and O_NDELAY.  */
  98.  
  99. #ifndef O_NDELAY
  100. #ifdef FNDELAY
  101. #define O_NDELAY FNDELAY
  102. #else /* ! defined (FNDELAY) */
  103. #define O_NDELAY 0
  104. #endif /* ! defined (FNDELAY) */
  105. #endif /* ! defined (O_NDELAY) */
  106.  
  107. #ifndef O_NONBLOCK
  108. #ifdef FNBLOCK
  109. #define O_NONBLOCK FNBLOCK
  110. #else /* ! defined (FNBLOCK) */
  111. #define O_NONBLOCK 0
  112. #endif /* ! defined (FNBLOCK) */
  113. #endif /* ! defined (O_NONBLOCK) */
  114.  
  115. #if O_NDELAY == 0 && O_NONBLOCK == 0
  116.  #error No way to do nonblocking I/O
  117. #endif
  118.  
  119. /* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA.  */
  120. #ifndef EAGAIN
  121. #ifndef EWOULDBLOCK
  122. #define EAGAIN (-1)
  123. #define EWOULDBLOCK (-1)
  124. #else /* defined (EWOULDBLOCK) */
  125. #define EAGAIN EWOULDBLOCK
  126. #endif /* defined (EWOULDBLOCK) */
  127. #else /* defined (EAGAIN) */
  128. #ifndef EWOULDBLOCK
  129. #define EWOULDBLOCK EAGAIN
  130. #endif /* ! defined (EWOULDBLOCK) */
  131. #endif /* defined (EAGAIN) */
  132.  
  133. #ifndef ENODATA
  134. #define ENODATA EAGAIN
  135. #endif
  136.  
  137. /* Make sure we have a CLK_TCK definition, even if it makes no sense.
  138.    This is in case TIMES_TICK is defined as CLK_TCK.  */
  139. #ifndef CLK_TCK
  140. #define CLK_TCK (60)
  141. #endif
  142.  
  143. /* Don't try too hard to get a TIMES_TICK value; it doesn't matter
  144.    that much.  */
  145. #if TIMES_TICK == 0
  146. #undef TIMES_TICK
  147. #define TIMES_TICK CLK_TCK
  148. #endif
  149.  
  150. #if TIMES_DECLARATION_OK
  151. extern long times ();
  152. #endif
  153.  
  154. #ifndef SIGCHLD
  155. #define SIGCHLD SIGCLD
  156. #endif
  157.  
  158. #if 1
  159. #define ZUUCICO_CMD "login uucp"
  160. #define UUCICO_EXECL "/bin/login", "login", "uucp"
  161. #else
  162. #define ZUUCICO_CMD "su - nuucp"
  163. #define UUCICO_EXECL "/bin/su", "su", "-", "nuucp"
  164. #endif
  165.  
  166. #if ! HAVE_SELECT && ! HAVE_POLL
  167.  #error You need select or poll
  168. #endif
  169.  
  170. #if ! HAVE_REMOVE
  171. #undef remove
  172. #define remove unlink
  173. #endif
  174.  
  175. /* Buffer chain to hold data read from a uucico.  */
  176.  
  177. #define BUFCHARS (512)
  178.  
  179. struct sbuf
  180. {
  181.   struct sbuf *qnext;
  182.   int cstart;
  183.   int cend;
  184.   char ab[BUFCHARS];
  185. };
  186.   
  187. /* Local functions.  */
  188.  
  189. static void umake_file P((const char *zfile, int cextra));
  190. static void uprepare_test P((boolean fmake, int itest,
  191.                  boolean fcall_uucico,
  192.                  const char *zsys));
  193. static void ucheck_file P((const char *zfile, const char *zerr,
  194.                int cextra));
  195. static void ucheck_test P((int itest, boolean fcall_uucico));
  196. static RETSIGTYPE uchild P((int isig));
  197. static int cpshow P((char *z, int bchar));
  198. static void uchoose P((int *po1, int *po2));
  199. static long cread P((int o, struct sbuf **));
  200. static boolean fsend P((int o, int oslave, struct sbuf **));
  201. static boolean fwritable P((int o));
  202. static void xsystem P((const char *zcmd));
  203. static FILE *xfopen P((const char *zname, const char *zmode));
  204.  
  205. static char *zDebug;
  206. static int iTest;
  207. static boolean fCall_uucico;
  208. static int iPercent;
  209. static pid_t iPid1, iPid2;
  210. static int cFrom1, cFrom2;
  211. static char abLogout1[sizeof "tstout /dev/ptyp0"];
  212. static char abLogout2[sizeof "tstout /dev/ptyp0"];
  213. static char *zProtocols;
  214.  
  215. int
  216. main (argc, argv)
  217.      int argc;
  218.      char **argv;
  219. {
  220.   int iopt;
  221.   const char *zcmd1, *zcmd2;
  222.   const char *zsys;
  223.   boolean fmake = TRUE;
  224.   int omaster1, oslave1, omaster2, oslave2;
  225.   char abpty1[sizeof "/dev/ptyp0"];
  226.   char abpty2[sizeof "/dev/ptyp0"];
  227.   struct sbuf *qbuf1, *qbuf2;
  228.  
  229.   zcmd1 = NULL;
  230.   zcmd2 = NULL;
  231.   zsys = "test2";
  232.  
  233.   while ((iopt = getopt (argc, argv, "c:np:s:t:ux:1:2:")) != EOF)
  234.     {
  235.       switch (iopt)
  236.     {
  237.     case 'c':
  238.       zProtocols = optarg;
  239.       break;
  240.     case 'n':
  241.       fmake = FALSE;
  242.       break;
  243.     case 'p':
  244.       iPercent = (int) strtol (optarg, (char **) NULL, 10);
  245.       srand ((unsigned int) ixsysdep_time ((long *) NULL));
  246.       break;
  247.     case 's':
  248.       zsys = optarg;
  249.       break;
  250.     case 't':
  251.       iTest = (int) strtol (optarg, (char **) NULL, 10);
  252.       break;
  253.     case 'u':
  254.       fCall_uucico = TRUE;
  255.       break;
  256.     case 'x':
  257.       zDebug = optarg;
  258.       break;
  259.     case '1':
  260.       zcmd1 = optarg;
  261.       break;
  262.     case '2':
  263.       zcmd2 = optarg;
  264.       break;
  265.     default:
  266.       fprintf (stderr,
  267.            "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
  268.            VERSION);
  269.       fprintf (stderr,
  270.            "Usage: tstuu [-xn] [-t #] [-u] [-1 cmd] [-2 cmd]\n");
  271.       exit (EXIT_FAILURE);
  272.     }
  273.     }
  274.  
  275.   if (fCall_uucico && zcmd2 == NULL)
  276.     zcmd2 = ZUUCICO_CMD;
  277.  
  278.   uprepare_test (fmake, iTest, fCall_uucico, zsys);
  279.  
  280.   (void) remove ("/usr/tmp/tstuu/spool1/core");
  281.   (void) remove ("/usr/tmp/tstuu/spool2/core");
  282.  
  283.   omaster1 = -1;
  284.   oslave1 = -1;
  285.   omaster2 = -1;
  286.   oslave2 = -1;
  287.  
  288. #if ! HAVE_STREAMS_PTYS
  289.  
  290.   {
  291.     char *zptyname;
  292.     const char *zpty;
  293.  
  294.     zptyname = abpty1;
  295.  
  296.     for (zpty = "pqrs"; *zpty != '\0'; ++zpty)
  297.       {
  298.     int ipty;
  299.  
  300.     for (ipty = 0; ipty < 16; ipty++)
  301.       {
  302.         int om, os;
  303.         FILE *e;
  304.   
  305.         sprintf (zptyname, "/dev/pty%c%c", *zpty,
  306.              "0123456789abcdef"[ipty]);
  307.         om = open (zptyname, O_RDWR);
  308.         if (om < 0)
  309.           continue;
  310.         zptyname[5] = 't';
  311.         os = open (zptyname, O_RDWR);
  312.         if (os < 0)
  313.           {
  314.         (void) close (om);
  315.         continue;
  316.           }
  317.  
  318.         if (omaster1 == -1)
  319.           {
  320.         omaster1 = om;
  321.         oslave1 = os;
  322.  
  323.         e = fopen ("/usr/tmp/tstuu/pty1", "w");
  324.         if (e == NULL)
  325.           {
  326.             perror ("fopen");
  327.             exit (EXIT_FAILURE);
  328.           }
  329.         fprintf (e, "%s", zptyname + 5);
  330.         if (fclose (e) != 0)
  331.           {
  332.             perror ("fclose");
  333.             exit (EXIT_FAILURE);
  334.           }
  335.  
  336.         zptyname = abpty2;
  337.           }
  338.         else
  339.           {
  340.         omaster2 = om;
  341.         oslave2 = os;
  342.  
  343.         e = fopen ("/usr/tmp/tstuu/pty2", "w");
  344.         if (e == NULL)
  345.           {
  346.             perror ("fopen");
  347.             exit (EXIT_FAILURE);
  348.           }
  349.         fprintf (e, "%s", zptyname + 5);
  350.         if (fclose (e) != 0)
  351.           {
  352.             perror ("fclose");
  353.             exit (EXIT_FAILURE);
  354.           }
  355.         break;
  356.           }
  357.       }
  358.  
  359.     if (omaster1 != -1 && omaster2 != -1)
  360.       break;
  361.       }
  362.   }
  363.  
  364. #else /* HAVE_STREAMS_PTYS */
  365.  
  366.   {
  367.     int ipty;
  368.  
  369.     for (ipty = 0; ipty < 2; ipty++)
  370.       {
  371.     int om, os;
  372.     FILE *e;
  373.     char *znam;
  374.     struct termio stio;
  375.  
  376.     om = open ((char *) "/dev/ptmx", O_RDWR);
  377.     if (om < 0)
  378.       break;
  379.     znam = ptsname (om);
  380.     if (znam == NULL)
  381.       break;
  382.     if (unlockpt (om) != 0
  383.         || grantpt (om) != 0)
  384.       break;
  385.  
  386.     os = open (znam, O_RDWR);
  387.     if (os < 0)
  388.       {
  389.         (void) close (om);
  390.         om = -1;
  391.         break;
  392.       }
  393.  
  394.     if (ioctl (os, I_PUSH, "ptem") < 0
  395.         || ioctl(os, I_PUSH, "ldterm") < 0)
  396.       {
  397.         perror ("ioctl");
  398.         exit (EXIT_FAILURE);
  399.       }
  400.  
  401.     /* Can this really be right? */
  402.     memset (&stio, 0, sizeof (stio));
  403.     stio.c_cflag = B9600 | CS8 | CREAD | HUPCL;
  404.  
  405.     if (ioctl(os, TCSETA, &stio) < 0)
  406.       {
  407.         perror ("TCSETA");
  408.         exit (EXIT_FAILURE);
  409.       }
  410.  
  411.     if (omaster1 == -1)
  412.       {
  413.         strcpy (abpty1, znam);
  414.         omaster1 = om;
  415.         oslave1 = os;
  416.         e = fopen ("/usr/tmp/tstuu/pty1", "w");
  417.         if (e == NULL)
  418.           {
  419.         perror ("fopen");
  420.         exit (EXIT_FAILURE);
  421.           }
  422.         fprintf (e, "%s", znam + 5);
  423.         if (fclose (e) != 0)
  424.           {
  425.         perror ("fclose");
  426.         exit (EXIT_FAILURE);
  427.           }
  428.       }
  429.     else
  430.       {
  431.         strcpy (abpty2, znam);
  432.         omaster2 = om;
  433.         oslave2 = os;
  434.         e = fopen ("/usr/tmp/tstuu/pty2", "w");
  435.         if (e == NULL)
  436.           {
  437.         perror ("fopen");
  438.         exit (EXIT_FAILURE);
  439.           }
  440.         fprintf (e, "%s", znam + 5);
  441.         if (fclose (e) != 0)
  442.           {
  443.         perror ("fclose");
  444.         exit (EXIT_FAILURE);
  445.           }
  446.       }
  447.       }
  448.   }
  449.  
  450. #endif /* HAVE_STREAMS_PTYS */
  451.  
  452.   if (omaster2 == -1)
  453.     {
  454.       fprintf (stderr, "No pseudo-terminals available\n");
  455.       exit (EXIT_FAILURE);
  456.     }
  457.  
  458.   /* Make sure we can or these into an int for the select call.  Most
  459.      systems could use 31 instead of 15, but it should never be a
  460.      problem.  */
  461.   if (omaster1 > 15 || omaster2 > 15)
  462.     {
  463.       fprintf (stderr, "File descriptors are too large\n");
  464.       exit (EXIT_FAILURE);
  465.     }
  466.  
  467.   /* Prepare to log out the command if it is a login command.  On
  468.      Ultrix 4.0 uucico can only be run from login for some reason.  */
  469.  
  470.   if (zcmd1 == NULL
  471.       || strncmp (zcmd1, "login", sizeof "login" - 1) != 0)
  472.     abLogout1[0] = '\0';
  473.   else
  474.     sprintf (abLogout1, "tstout %s", abpty1);
  475.  
  476.   if (zcmd2 == NULL
  477.       || strncmp (zcmd2, "login", sizeof "login" - 1) != 0)
  478.     abLogout2[0] = '\0';
  479.   else
  480.     sprintf (abLogout2, "tstout %s", abpty2);
  481.  
  482.   iPid1 = fork ();
  483.   if (iPid1 < 0)
  484.     {
  485.       perror ("fork");
  486.       exit (EXIT_FAILURE);
  487.     }
  488.   else if (iPid1 == 0)
  489.     {
  490.       if (close (0) < 0
  491.       || close (1) < 0
  492.       || close (omaster1) < 0
  493.       || close (omaster2) < 0
  494.       || close (oslave2) < 0)
  495.     perror ("close");
  496.  
  497.       if (dup2 (oslave1, 0) < 0
  498.       || dup2 (oslave1, 1) < 0)
  499.     perror ("dup2");
  500.  
  501.       if (close (oslave1) < 0)
  502.     perror ("close");
  503.  
  504.       if (zDebug != NULL)
  505.     fprintf (stderr, "About to exec first process\n");
  506.  
  507.       if (zcmd1 != NULL)
  508.     exit (system ((char *) zcmd1));
  509.       else
  510.     {
  511.       (void) execl ("uucico", "uucico", "-I", "/usr/tmp/tstuu/Config1",
  512.             "-q", "-S", zsys, "-pstdin", (const char *) NULL);
  513.       perror ("execl failed");
  514.       exit (EXIT_FAILURE);
  515.     }
  516.     }
  517.  
  518.   iPid2 = fork ();
  519.   if (iPid2 < 0)
  520.     {
  521.       perror ("fork");
  522.       kill (iPid1, SIGTERM);
  523.       exit (EXIT_FAILURE);
  524.     }
  525.   else if (iPid2 == 0)
  526.     {
  527.       if (close (0) < 0
  528.       || close (1) < 0
  529.       || close (omaster1) < 0
  530.       || close (oslave1) < 0
  531.       || close (omaster2) < 0)
  532.     perror ("close");
  533.  
  534.       if (dup2 (oslave2, 0) < 0
  535.       || dup2 (oslave2, 1) < 0)
  536.     perror ("dup2");
  537.  
  538.       if (close (oslave2) < 0)
  539.     perror ("close");
  540.  
  541.       if (zDebug != NULL)
  542.     fprintf (stderr, "About to exec second process\n");
  543.  
  544.       if (fCall_uucico)
  545.     {
  546.       (void) execl (UUCICO_EXECL, (const char *) NULL);
  547.       perror ("execl failed");
  548.       exit (EXIT_FAILURE);
  549.     }
  550.       else if (zcmd2 != NULL)
  551.     exit (system ((char *) zcmd2));
  552.       else
  553.     {
  554.       (void) execl ("uucico", "uucico", "-I", "/usr/tmp/tstuu/Config2",
  555.             "-lq", (const char *)NULL);
  556.       perror ("execl failed");
  557.       exit (EXIT_FAILURE);
  558.     }
  559.     }
  560.  
  561.   signal (SIGCHLD, uchild);
  562.  
  563.   if (fcntl (omaster1, F_SETFL, O_NDELAY | O_NONBLOCK) < 0
  564.       && errno == EINVAL)
  565.     (void) fcntl (omaster1, F_SETFL, O_NONBLOCK);
  566.   if (fcntl (omaster2, F_SETFL, O_NDELAY | O_NONBLOCK) < 0
  567.       && errno == EINVAL)
  568.     (void) fcntl (omaster2, F_SETFL, O_NONBLOCK);
  569.  
  570.   qbuf1 = NULL;
  571.   qbuf2 = NULL;
  572.  
  573.   while (TRUE)
  574.     {
  575.       int o1, o2;
  576.       boolean fcont;
  577.  
  578.       o1 = omaster1;
  579.       o2 = omaster2;
  580.       uchoose (&o1, &o2);
  581.  
  582.       if (o1 == -1 && o2 == -1)
  583.     {
  584.       if (zDebug != NULL)
  585.         fprintf (stderr, "Five second pause\n");
  586.       continue;
  587.     }
  588.  
  589.       if (o1 != -1)
  590.     cFrom1 += cread (omaster1, &qbuf1);
  591.  
  592.       if (o2 != -1)
  593.     cFrom2 += cread (omaster2, &qbuf2);
  594.  
  595.       do
  596.     {
  597.       fcont = FALSE;
  598.  
  599.       if (qbuf1 != NULL
  600.           && fwritable (omaster2)
  601.           && fsend (omaster2, oslave2, &qbuf1))
  602.         fcont = TRUE;
  603.  
  604.       if (qbuf2 != NULL
  605.           && fwritable (omaster1)
  606.           && fsend (omaster1, oslave1, &qbuf2))
  607.         fcont = TRUE;
  608.  
  609.       if (! fcont
  610.           && (qbuf1 != NULL || qbuf2 != NULL))
  611.         {
  612.           long cgot1, cgot2;
  613.  
  614.           cgot1 = cread (omaster1, &qbuf1);
  615.           cFrom1 += cgot1;
  616.           cgot2 = cread (omaster2, &qbuf2);
  617.           cFrom2 += cgot2;
  618.           fcont = TRUE;
  619.         }
  620.     }
  621.       while (fcont);
  622.     }
  623.  
  624.   /*NOTREACHED*/
  625. }
  626.  
  627. /* When a child dies, kill them both.  */
  628.  
  629. static RETSIGTYPE
  630. uchild (isig)
  631.      int isig;
  632. {
  633.   struct tms sbase, s1, s2;
  634.  
  635.   signal (SIGCHLD, SIG_DFL);
  636.  
  637.   /* Give the processes a chance to die on their own.  */
  638.   sleep (2);
  639.  
  640.   (void) kill (iPid1, SIGTERM);
  641.   (void) kill (iPid2, SIGTERM);
  642.  
  643.   (void) times (&sbase);
  644.  
  645. #if HAVE_WAITPID
  646.   (void) waitpid (iPid1, (pointer) NULL, 0);
  647. #else /* ! HAVE_WAITPID */
  648. #if HAVE_WAIT4
  649.   (void) wait4 (iPid1, (pointer) NULL, 0, (struct rusage *) NULL);
  650. #else /* ! HAVE_WAIT4 */
  651.   (void) wait ((wait_status *) NULL);
  652. #endif /* ! HAVE_WAIT4 */
  653. #endif /* ! HAVE_WAITPID */
  654.  
  655.   (void) times (&s1);
  656.  
  657. #if HAVE_WAITPID
  658.   (void) waitpid (iPid2, (pointer) NULL, 0);
  659. #else /* ! HAVE_WAITPID */
  660. #if HAVE_WAIT4
  661.   (void) wait4 (iPid2, (wait_status *) NULL, 0, (struct rusage *) NULL);
  662. #else /* ! HAVE_WAIT4 */
  663.   (void) wait ((wait_status *) NULL);
  664. #endif /* ! HAVE_WAIT4 */
  665. #endif /* ! HAVE_WAITPID */
  666.  
  667.   (void) times (&s2);
  668.  
  669.   fprintf (stderr,
  670.        " First child: user: %g; system: %g\n",
  671.        (double) (s1.tms_cutime - sbase.tms_cutime) / (double) TIMES_TICK,
  672.        (double) (s1.tms_cstime - sbase.tms_cstime) / (double) TIMES_TICK);
  673.   fprintf (stderr,
  674.        "Second child: user: %g; system: %g\n",
  675.        (double) (s2.tms_cutime - s1.tms_cutime) / (double) TIMES_TICK,
  676.        (double) (s2.tms_cstime - s1.tms_cstime) / (double) TIMES_TICK);
  677.  
  678.   ucheck_test (iTest, fCall_uucico);
  679.  
  680.   if (abLogout1[0] != '\0')
  681.     {
  682.       if (zDebug != NULL)
  683.     fprintf (stderr, "Executing %s\n", abLogout1);
  684.       (void) system (abLogout1);
  685.     }
  686.   if (abLogout2[0] != '\0')
  687.     {
  688.       if (zDebug != NULL)
  689.     fprintf (stderr, "Executing %s\n", abLogout2);
  690.       (void) system (abLogout2);
  691.     }
  692.  
  693.   fprintf (stderr, "Wrote %d bytes from 1 to 2\n", cFrom1);
  694.   fprintf (stderr, "Wrote %d bytes from 2 to 1\n", cFrom2);
  695.  
  696.   if (access ("/usr/tmp/tstuu/spool1/core", R_OK) == 0)
  697.     fprintf (stderr, "core file 1 exists\n");
  698.   if (access ("/usr/tmp/tstuu/spool2/core", R_OK) == 0)
  699.     fprintf (stderr, "core file 2 exists\n");
  700.  
  701.   exit (EXIT_SUCCESS);
  702. }
  703.  
  704. /* Open a file without error.  */
  705.  
  706. static FILE *
  707. xfopen (zname, zmode)
  708.      const char *zname;
  709.      const char *zmode;
  710. {
  711.   FILE *eret;
  712.  
  713.   eret = fopen (zname, zmode);
  714.   if (eret == NULL)
  715.     {
  716.       perror (zname);
  717.       exit (EXIT_FAILURE);
  718.     }
  719.   return eret;
  720. }
  721.  
  722. /* Close a file without error.  */
  723.  
  724. static void xfclose P((FILE *e));
  725.  
  726. static void
  727. xfclose (e)
  728.      FILE *e;
  729. {
  730.   if (fclose (e) != 0)
  731.     {
  732.       perror ("fclose");
  733.       exit (EXIT_FAILURE);
  734.     }
  735. }
  736.  
  737. /* Create a test file.  */
  738.  
  739. static void
  740. umake_file (z, c)
  741.      const char *z;
  742.      int c;
  743. {
  744.   int i;
  745.   FILE *e;
  746.  
  747.   e = xfopen (z, "w");
  748.     
  749.   for (i = 0; i < 256; i++)
  750.     {
  751.       int i2;
  752.  
  753.       for (i2 = 0; i2 < 256; i2++)
  754.     putc (i, e);
  755.     }
  756.  
  757.   for (i = 0; i < c; i++)
  758.     putc (i, e);
  759.  
  760.   xfclose (e);
  761. }
  762.  
  763. /* Check a test file.  */
  764.  
  765. static void
  766. ucheck_file (z, zerr, c)
  767.      const char *z;
  768.      const char *zerr;
  769.      int c;
  770. {
  771.   int i;
  772.   FILE *e;
  773.  
  774.   e = xfopen (z, "r");
  775.  
  776.   for (i = 0; i < 256; i++)
  777.     {
  778.       int i2;
  779.  
  780.       for (i2 = 0; i2 < 256; i2++)
  781.     {
  782.       int bread;
  783.  
  784.       bread = getc (e);
  785.       if (bread == EOF)
  786.         {
  787.           fprintf (stderr,
  788.                "%s: Unexpected EOF at position %d,%d\n",
  789.                zerr, i, i2);
  790.           xfclose (e);
  791.           return;
  792.         }
  793.       if (bread != i)
  794.         fprintf (stderr,
  795.              "%s: At position %d,%d got %d expected %d\n",
  796.              zerr, i, i2, bread, i);
  797.     }
  798.     }
  799.  
  800.   for (i = 0; i < c; i++)
  801.     {
  802.       int bread;
  803.  
  804.       bread = getc (e);
  805.       if (bread == EOF)
  806.     {
  807.       fprintf (stderr, "%s: Unexpected EOF at extra %d\n", zerr, i);
  808.       xfclose (e);
  809.       return;
  810.     }
  811.       if (bread != i)
  812.     fprintf (stderr, "%s: At extra %d got %d expected %d\n",
  813.          zerr, i, bread, i);
  814.     }
  815.  
  816.   if (getc (e) != EOF)
  817.     fprintf (stderr, "%s: File is too long", zerr);
  818.  
  819.   xfclose (e);
  820. }
  821.  
  822. /* Prepare all the configuration files for testing.  */
  823.  
  824. static void
  825. uprepare_test (fmake, itest, fcall_uucico, zsys)
  826.      boolean fmake;
  827.      int itest;
  828.      boolean fcall_uucico;
  829.      const char *zsys;
  830. {
  831.   FILE *e;
  832.   const char *zuucp1, *zuucp2;
  833.   const char *zuux1, *zuux2;
  834.   char ab[1000];
  835.   const char *zfrom;
  836.   const char *zto;
  837.  
  838. /* We must make /usr/tmp/tstuu world writeable or we won't be able to
  839.    receive files into it.  */
  840.   (void) umask (0);
  841.  
  842. #ifndef S_IWOTH
  843. #define S_IWOTH 02
  844. #endif
  845.  
  846.   if (mkdir ((char *) "/usr/tmp/tstuu",
  847.          IPUBLIC_DIRECTORY_MODE | S_IWOTH) != 0
  848.       && errno != EEXIST)
  849.     {
  850.       perror ("mkdir");
  851.       exit (EXIT_FAILURE);
  852.     }
  853.  
  854.   if (mkdir ((char *) "/usr/tmp/tstuu/spool1", IPUBLIC_DIRECTORY_MODE) != 0
  855.       && errno != EEXIST)
  856.     {
  857.       perror ("mkdir");
  858.       exit (EXIT_FAILURE);
  859.     }
  860.  
  861.   if (mkdir ((char *) "/usr/tmp/tstuu/spool2", IPUBLIC_DIRECTORY_MODE) != 0
  862.       && errno != EEXIST)
  863.     {
  864.       perror ("mkdir");
  865.       exit (EXIT_FAILURE);
  866.     }
  867.  
  868.   if (fmake)
  869.     {
  870.       e = xfopen ("/usr/tmp/tstuu/Config1", "w");
  871.  
  872.       fprintf (e, "# First test configuration file\n");
  873.       fprintf (e, "nodename test1\n");
  874.       fprintf (e, "spool /usr/tmp/tstuu/spool1\n");
  875.       fprintf (e, "lockdir /usr/tmp/tstuu/spool1\n");
  876.       fprintf (e, "sysfile /usr/tmp/tstuu/System1\n");
  877.       fprintf (e, "sysfile /usr/tmp/tstuu/System1.2\n");
  878.       fprintf (e, "portfile /usr/tmp/tstuu/Port1\n");
  879.       (void) remove ("/usr/tmp/tstuu/Log1");
  880. #if ! HAVE_HDB_LOGGING
  881.       fprintf (e, "logfile /usr/tmp/tstuu/Log1\n");
  882. #else
  883.       fprintf (e, "%s\n", "logfile /usr/tmp/tstuu/Log1/%s/%s");
  884. #endif
  885.       fprintf (e, "statfile /usr/tmp/tstuu/Stats1\n");
  886.       fprintf (e, "debugfile /usr/tmp/tstuu/Debug1\n");
  887.       fprintf (e, "callfile /usr/tmp/tstuu/Call1\n");
  888.       fprintf (e, "pubdir /usr/tmp/tstuu\n");
  889. #if HAVE_V2_CONFIG
  890.       fprintf (e, "v2-files no\n");
  891. #endif
  892. #if HAVE_HDB_CONFIG
  893.       fprintf (e, "hdb-files no\n");
  894. #endif
  895.       if (zDebug != NULL)
  896.     fprintf (e, "debug %s\n", zDebug);
  897.  
  898.       xfclose (e);
  899.  
  900.       e = xfopen ("/usr/tmp/tstuu/System1", "w");
  901.  
  902.       fprintf (e, "# This file is ignored, to test multiple system files\n");
  903.       fprintf (e, "time never\n");
  904.  
  905.       xfclose (e);
  906.  
  907.       e = xfopen ("/usr/tmp/tstuu/System1.2", "w");
  908.  
  909.       fprintf (e, "# First test system file\n");
  910.       fprintf (e, "time any\n");
  911.       fprintf (e, "port stdin\n");
  912.       fprintf (e, "# That was the defaults\n");
  913.       fprintf (e, "system %s\n", zsys);
  914.       if (! fcall_uucico)
  915.     {
  916.       FILE *eprog;
  917.  
  918.       eprog = xfopen ("/usr/tmp/tstuu/Chat1", "w");
  919.  
  920.       /* Wait for the other side to open the port and flush input.  */
  921.       fprintf (eprog, "sleep 2\n");
  922.       fprintf (eprog,
  923.            "echo password $1 speed $2 1>&2\n");
  924.       fprintf (eprog, "echo test1\n");
  925.       fprintf (eprog, "exit 0\n");
  926.  
  927.       xfclose (eprog);
  928.  
  929.       if (chmod ("/usr/tmp/tstuu/Chat1",
  930.              S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0)
  931.         {
  932.           perror ("chmod (/usr/tmp/tstuu/Chat1)");
  933.           exit (EXIT_FAILURE);
  934.         }
  935.  
  936.       fprintf (e, "chat-program /usr/tmp/tstuu/Chat1 \\P \\S\n");
  937.  
  938.       fprintf (e, "chat word: \\P\n");
  939.       fprintf (e, "chat-fail login;\n");
  940.       fprintf (e, "call-login *\n");
  941.       fprintf (e, "call-password *\n");
  942.     }
  943.       else
  944.     fprintf (e, "chat \"\"\n");
  945.       fprintf (e, "call-transfer yes\n");
  946.       fprintf (e, "commands cat\n");
  947.       if (! fcall_uucico && iPercent == 0)
  948.     {
  949.       fprintf (e, "protocol-parameter g window 7\n");
  950.       fprintf (e, "protocol-parameter g packet-size 4096\n");
  951.       fprintf (e, "protocol-parameter j avoid \\377\n");
  952.     }
  953.       if (zProtocols != NULL)
  954.     fprintf (e, "protocol %s\n", zProtocols);
  955.  
  956.       xfclose (e);
  957.  
  958.       e = xfopen ("/usr/tmp/tstuu/Port1", "w");
  959.  
  960.       fprintf (e, "port stdin\n");
  961.       fprintf (e, "type stdin\n");
  962.       fprintf (e, "pty true\n");
  963.  
  964.       xfclose (e);
  965.  
  966.       e = xfopen ("/usr/tmp/tstuu/Call1", "w");
  967.  
  968.       fprintf (e, "Call out password file\n");
  969.       fprintf (e, "%s test1 pass1\n", zsys);
  970.  
  971.       xfclose (e);
  972.  
  973.       if (! fcall_uucico)
  974.     {
  975.       FILE *eprog;
  976.  
  977.       e = xfopen ("/usr/tmp/tstuu/Config2", "w");
  978.  
  979.       fprintf (e, "# Second test configuration file\n");
  980.       fprintf (e, "nodename test2\n");
  981.       fprintf (e, "spool /usr/tmp/tstuu/spool2\n");
  982.       fprintf (e, "lockdir /usr/tmp/tstuu/spool2\n");
  983.       fprintf (e, "sysfile /usr/tmp/tstuu/System2\n");
  984.       (void) remove ("/usr/tmp/tstuu/Log2");
  985. #if ! HAVE_HDB_LOGGING
  986.       fprintf (e, "logfile /usr/tmp/tstuu/Log2\n");
  987. #else
  988.       fprintf (e, "%s\n", "logfile /usr/tmp/tstuu/Log2/%s/%s");
  989. #endif
  990.       fprintf (e, "statfile /usr/tmp/tstuu/Stats2\n");
  991.       fprintf (e, "debugfile /usr/tmp/tstuu/Debug2\n");
  992.       fprintf (e, "passwdfile /usr/tmp/tstuu/Pass2\n");
  993.       fprintf (e, "pubdir /usr/tmp/tstuu\n");
  994. #if HAVE_V2_CONFIG
  995.       fprintf (e, "v2-files no\n");
  996. #endif
  997. #if HAVE_HDB_CONFIG
  998.       fprintf (e, "hdb-files no\n");
  999. #endif
  1000.       if (zDebug != NULL)
  1001.         fprintf (e, "debug %s\n", zDebug);
  1002.  
  1003.       xfclose (e);
  1004.  
  1005.       e = xfopen ("/usr/tmp/tstuu/System2", "w");
  1006.  
  1007.       fprintf (e, "# Second test system file\n");
  1008.       fprintf (e, "system test1\n");
  1009.       fprintf (e, "called-login test1\n");
  1010.       fprintf (e, "request true\n");
  1011.       fprintf (e, "commands cat\n");
  1012.       if (zProtocols != NULL)
  1013.         fprintf (e, "protocol %s\n", zProtocols);
  1014.  
  1015.       eprog = xfopen ("/usr/tmp/tstuu/Chat2", "w");
  1016.  
  1017.       fprintf (eprog,
  1018.            "echo port $1 1>&2\n");
  1019.       fprintf (eprog, "exit 0\n");
  1020.  
  1021.       xfclose (eprog);
  1022.  
  1023.       if (chmod ("/usr/tmp/tstuu/Chat2",
  1024.              S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0)
  1025.         {
  1026.           perror ("chmod (/usr/tmp/tstuu/Chat2");
  1027.           exit (EXIT_FAILURE);
  1028.         }
  1029.  
  1030.       fprintf (e, "called-chat-program /bin/sh /usr/tmp/tstuu/Chat2 \\Y\n");
  1031.       fprintf (e, "time any\n");
  1032.  
  1033.       xfclose (e);
  1034.  
  1035.       e = xfopen ("/usr/tmp/tstuu/Pass2", "w");
  1036.  
  1037.       fprintf (e, "# Call in password file\n");
  1038.       fprintf (e, "test1 pass1\n");
  1039.  
  1040.       xfclose (e);
  1041.     }
  1042.     }
  1043.  
  1044.   zuucp1 = "./uucp -I /usr/tmp/tstuu/Config1 -r";
  1045.   zuux1 = "./uux -I /usr/tmp/tstuu/Config1 -r";
  1046.  
  1047.   if (fcall_uucico)
  1048.     {
  1049.       zuucp2 = "/usr/bin/uucp -r";
  1050.       zuux2 = "/usr/bin/uux -r";
  1051.     }
  1052.   else
  1053.     {
  1054.       zuucp2 = "./uucp -I /usr/tmp/tstuu/Config2 -r";
  1055.       zuux2 = "./uux -I /usr/tmp/tstuu/Config2 -r";
  1056.     }
  1057.  
  1058.   /* Test transferring a file from the first system to the second.  */
  1059.   if (itest == 0 || itest == 1)
  1060.     {
  1061.       zfrom = "/usr/tmp/tstuu/from1";
  1062.       if (fcall_uucico)
  1063.     zto = "/usr/spool/uucppublic/to1";
  1064.       else
  1065.     zto = "/usr/tmp/tstuu/to1";
  1066.  
  1067.       (void) remove (zto);
  1068.       umake_file (zfrom, 0);
  1069.  
  1070.       sprintf (ab, "%s %s %s!%s", zuucp1, zfrom, zsys, zto);
  1071.       xsystem (ab);
  1072.     }
  1073.  
  1074.   /* Test having the first system request a file from the second.  */
  1075.   if (itest == 0 || itest == 2)
  1076.     {
  1077.       if (fcall_uucico)
  1078.     zfrom = "/usr/spool/uucppublic/from2";
  1079.       else
  1080.     zfrom = "/usr/tmp/tstuu/from2";
  1081.       zto = "/usr/tmp/tstuu/to2";
  1082.  
  1083.       (void) remove (zto);
  1084.       umake_file (zfrom, 3);
  1085.  
  1086.       sprintf (ab, "%s %s!%s %s", zuucp1, zsys, zfrom, zto);
  1087.       xsystem (ab);
  1088.     }
  1089.  
  1090.   /* Test having the second system send a file to the first.  */
  1091.   if (itest == 0 || itest == 3)
  1092.     {
  1093.       if (fcall_uucico)
  1094.     zfrom = "/usr/spool/uucppublic/from3";
  1095.       else
  1096.     zfrom = "/usr/tmp/tstuu/from3";
  1097.       zto = "/usr/tmp/tstuu/to3";
  1098.  
  1099.       (void) remove (zto);
  1100.       umake_file (zfrom, 5);
  1101.  
  1102.       sprintf (ab, "%s -c \\~/from3 test1!~/to3", zuucp2);
  1103.       xsystem (ab);
  1104.     }
  1105.  
  1106.   /* Test having the second system request a file from the first.  */
  1107.   if (itest == 0 || itest == 4)
  1108.     {
  1109.       zfrom = "/usr/tmp/tstuu/from4";
  1110.       if (fcall_uucico)
  1111.     zto = "/usr/spool/uucppublic/to4";
  1112.       else
  1113.     zto = "/usr/tmp/tstuu/to4";
  1114.  
  1115.       (void) remove (zto);
  1116.       umake_file (zfrom, 7);
  1117.  
  1118.       sprintf (ab, "%s test1!%s %s", zuucp2, zfrom, zto);
  1119.       xsystem (ab);
  1120.     }
  1121.  
  1122.   /* Test having the second system make an execution request.  */
  1123.   if (itest == 0 || itest == 5)
  1124.     {
  1125.       zfrom = "/usr/tmp/tstuu/from5";
  1126.       if (fcall_uucico)
  1127.     zto = "/usr/spool/uucppublic/to5";
  1128.       else
  1129.     zto = "/usr/tmp/tstuu/to5";
  1130.  
  1131.       (void) remove (zto);
  1132.       umake_file (zfrom, 11);
  1133.  
  1134.       sprintf (ab, "%s test1!cat '<%s' '>%s'", zuux2, zfrom, zto);
  1135.       xsystem (ab);
  1136.     }
  1137.  
  1138.   /* Test having the first system request a wildcard.  */
  1139.   if (itest == 0 || itest == 6)
  1140.     {
  1141.       const char *zfrom1, *zfrom2;
  1142.  
  1143.       if (fcall_uucico)
  1144.     {
  1145.       zfrom = "/usr/spool/uucppublic/to6\\*";
  1146.       zfrom1 = "/usr/spool/uucppublic/to6.1";
  1147.       zfrom2 = "/usr/spool/uucppublic/to6.2";
  1148.     }
  1149.       else
  1150.     {
  1151.       zfrom = "/usr/tmp/tstuu/spool2/to6\\*";
  1152.       zfrom1 = "/usr/tmp/tstuu/spool2/to6.1";
  1153.       zfrom2 = "/usr/tmp/tstuu/spool2/to6.2";
  1154.     }
  1155.  
  1156.       umake_file (zfrom1, 100);
  1157.       umake_file (zfrom2, 101);
  1158.       (void) remove ("/usr/tmp/tstuu/to6.1");
  1159.       (void) remove ("/usr/tmp/tstuu/to6.2");
  1160.  
  1161.       sprintf (ab, "%s %s!%s /usr/tmp/tstuu", zuucp1, zsys, zfrom);
  1162.       xsystem (ab);
  1163.     }
  1164.  
  1165.   /* Test having the second system request a wildcard.  */
  1166.   if (itest == 0 || itest == 7)
  1167.     {
  1168.       const char *zto1, *zto2;
  1169.  
  1170.       if (fcall_uucico)
  1171.     {
  1172.       zto = "/usr/spool/uucppublic";
  1173.       zto1 = "/usr/spool/uucppublic/to7.1";
  1174.       zto2 = "/usr/spool/uucppublic/to7.2";
  1175.     }
  1176.       else
  1177.     {
  1178.       zto = "/usr/tmp/tstuu";
  1179.       zto1 = "/usr/tmp/tstuu/to7.1";
  1180.       zto2 = "/usr/tmp/tstuu/to7.2";
  1181.     }
  1182.  
  1183.       umake_file ("/usr/tmp/tstuu/spool1/to7.1", 150);
  1184.       umake_file ("/usr/tmp/tstuu/spool1/to7.2", 155);
  1185.       (void) remove (zto1);
  1186.       (void) remove (zto2);
  1187.  
  1188.       sprintf (ab, "%s test1!/usr/tmp/tstuu/spool1/to7.\\* %s", zuucp2,
  1189.            zto);
  1190.       xsystem (ab);
  1191.     }
  1192.  
  1193.   /* Test an E command.  This runs cat, discarding the output.  */
  1194.   if ((itest == 0 || itest == 8) && ! fcall_uucico)
  1195.     {
  1196.       umake_file ("/usr/tmp/tstuu/from8", 30);
  1197.       sprintf (ab, "%s - test2!cat < /usr/tmp/tstuu/from8", zuux1);
  1198.       xsystem (ab);
  1199.     }
  1200. }
  1201.  
  1202. /* Try to make sure the file transfers were successful.  */
  1203.  
  1204. static void
  1205. ucheck_test (itest, fcall_uucico)
  1206.      int itest;
  1207.      boolean fcall_uucico;
  1208. {
  1209.   if (itest == 0 || itest == 1)
  1210.     {
  1211.       if (fcall_uucico)
  1212.     ucheck_file ("/usr/spool/uucppublic/to1", "test 1", 0);
  1213.       else
  1214.     ucheck_file ("/usr/tmp/tstuu/to1", "test 1", 0);
  1215.     }
  1216.  
  1217.   if (itest == 0 || itest == 2)
  1218.     ucheck_file ("/usr/tmp/tstuu/to2", "test 2", 3);
  1219.  
  1220.   if (itest == 0 || itest == 3)
  1221.     ucheck_file ("/usr/tmp/tstuu/to3", "test 3", 5);
  1222.  
  1223.   if (itest == 0 || itest == 4)
  1224.     {
  1225.       if (fcall_uucico)
  1226.     ucheck_file ("/usr/spool/uucppublic/to4", "test 4", 7);
  1227.       else
  1228.     ucheck_file ("/usr/tmp/tstuu/to4", "test 4", 7);
  1229.     }
  1230.  
  1231.   if (itest == 0 || itest == 6)
  1232.     {
  1233.       ucheck_file ("/usr/tmp/tstuu/to6.1", "test 6.1", 100);
  1234.       ucheck_file ("/usr/tmp/tstuu/to6.2", "test 6.2", 101);
  1235.     }
  1236.  
  1237.   if (itest == 0 || itest == 7)
  1238.     {
  1239.       const char *zto1, *zto2;
  1240.  
  1241.       if (fcall_uucico)
  1242.     {
  1243.       zto1 = "/usr/spool/uucppublic/to7.1";
  1244.       zto2 = "/usr/spool/uucppublic/to7.2";
  1245.     }
  1246.       else
  1247.     {
  1248.       zto1 = "/usr/tmp/tstuu/to7.1";
  1249.       zto2 = "/usr/tmp/tstuu/to7.2";
  1250.     }
  1251.  
  1252.       ucheck_file (zto1, "test 7.1", 150);
  1253.       ucheck_file (zto2, "test 7.2", 155);
  1254.     }
  1255. }
  1256.  
  1257. /* A debugging routine used when displaying buffers.  */
  1258.  
  1259. static int
  1260. cpshow (z, ichar)
  1261.      char *z;
  1262.      int ichar;
  1263. {
  1264.   if (isprint (BUCHAR (ichar)) && ichar != '\"')
  1265.     {
  1266.       *z = (char) ichar;
  1267.       return 1;
  1268.     }
  1269.  
  1270.   *z++ = '\\';
  1271.  
  1272.   switch (ichar)
  1273.     {
  1274.     case '\n':
  1275.       *z = 'n';
  1276.       return 2;
  1277.     case '\r':
  1278.       *z = 'r';
  1279.       return 2;
  1280.     case '\"':
  1281.       *z = '\"';
  1282.       return 2;
  1283.     default:
  1284.       sprintf (z, "%03o", (unsigned int)(ichar & 0xff));
  1285.       return strlen (z) + 1;
  1286.     }
  1287. }      
  1288.  
  1289. /* Pick one of two file descriptors which is ready for reading, or
  1290.    return in five seconds.  If the argument is ready for reading,
  1291.    leave it alone; otherwise set it to -1.  */
  1292.  
  1293. static void
  1294. uchoose (po1, po2)
  1295.      int *po1;
  1296.      int *po2;
  1297. {
  1298. #if HAVE_SELECT
  1299.  
  1300.   int iread;
  1301.   struct timeval stime;
  1302.  
  1303.   iread = (1 << *po1) | (1 << *po2);
  1304.   stime.tv_sec = 5;
  1305.   stime.tv_usec = 0;
  1306.  
  1307.   if (select ((*po1 > *po2 ? *po1 : *po2) + 1, (pointer) &iread,
  1308.           (pointer) NULL, (pointer) NULL, &stime) < 0)
  1309.     {
  1310.       perror ("select");
  1311.       uchild (SIGCHLD);
  1312.     }
  1313.  
  1314.   if ((iread & (1 << *po1)) == 0)
  1315.     *po1 = -1;
  1316.  
  1317.   if ((iread & (1 << *po2)) == 0)
  1318.     *po2 = -1;
  1319.  
  1320. #else /* ! HAVE_SELECT */
  1321.  
  1322. #if HAVE_POLL
  1323.  
  1324.   struct pollfd as[2];
  1325.  
  1326.   as[0].fd = *po1;
  1327.   as[0].events = POLLIN;
  1328.   as[1].fd = *po2;
  1329.   as[1].events = POLLIN;
  1330.  
  1331.   if (poll (as, 2, 5 * 1000) < 0)
  1332.     {
  1333.       perror ("poll");
  1334.       uchild (SIGCHLD);
  1335.     }
  1336.  
  1337.   if ((as[0].revents & POLLIN) == 0)
  1338.     *po1 = -1;
  1339.   
  1340.   if ((as[1].revents & POLLIN) == 0)
  1341.     *po2 = -1;
  1342.  
  1343. #endif /* HAVE_POLL */
  1344. #endif /* ! HAVE_SELECT */
  1345. }
  1346.  
  1347. /* Read some data from a file descriptor.  This keeps reading until
  1348.    one of the reads gets no data.  */
  1349.  
  1350. static long
  1351. cread (o, pqbuf)
  1352.      int o;
  1353.      struct sbuf **pqbuf;
  1354. {
  1355.   long ctotal;
  1356.  
  1357.   while (*pqbuf != NULL && (*pqbuf)->qnext != NULL)
  1358.     pqbuf = &(*pqbuf)->qnext;
  1359.  
  1360.   ctotal = 0;
  1361.  
  1362.   while (TRUE)
  1363.     {
  1364.       int cgot;
  1365.  
  1366.       if (*pqbuf != NULL
  1367.       && (*pqbuf)->cend >= sizeof (*pqbuf)->ab)
  1368.     pqbuf = &(*pqbuf)->qnext;
  1369.  
  1370.       if (*pqbuf == NULL)
  1371.     {
  1372.       *pqbuf = (struct sbuf *) malloc (sizeof (struct sbuf));
  1373.       if (*pqbuf == NULL)
  1374.         {
  1375.           fprintf (stderr, "Out of memory\n");
  1376.           uchild (SIGCHLD);
  1377.         }
  1378.       (*pqbuf)->qnext = NULL;
  1379.       (*pqbuf)->cstart = 0;
  1380.       (*pqbuf)->cend = 0;
  1381.     }
  1382.       
  1383.       cgot = read (o, (*pqbuf)->ab + (*pqbuf)->cend,
  1384.            (sizeof (*pqbuf)->ab) - (*pqbuf)->cend);
  1385.       if (cgot < 0)
  1386.     {
  1387.       if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA)
  1388.         cgot = 0;
  1389.       else
  1390.         {
  1391.           perror ("read");
  1392.           uchild (SIGCHLD);
  1393.         }
  1394.     }
  1395.  
  1396.       if (cgot == 0)
  1397.     return ctotal;
  1398.  
  1399.       ctotal += cgot;
  1400.  
  1401.       if (zDebug != NULL)
  1402.     {
  1403.       char abshow[325];
  1404.       char *zfrom;
  1405.       char *zshow;
  1406.       int i;
  1407.  
  1408.       zfrom = (*pqbuf)->ab + (*pqbuf)->cend;
  1409.       zshow = abshow;
  1410.       for (i = 0; i < cgot && i < 80; i++, zfrom++)
  1411.         zshow += cpshow (zshow, *zfrom);
  1412.       if (i < cgot)
  1413.         {
  1414.           *zshow++ = '.';
  1415.           *zshow++ = '.';
  1416.           *zshow++ = '.';
  1417.         }
  1418.       *zshow = '\0';
  1419.       fprintf (stderr, "Read from %d: %d \"%s\"\n", o, cgot, abshow);
  1420.       fflush (stderr);
  1421.     }
  1422.  
  1423.       if (iPercent > 0)
  1424.     {
  1425.       int i;
  1426.       int c;
  1427.  
  1428.       c = 0;
  1429.       for (i = 0; i < cgot; i++)
  1430.         {
  1431.           if (rand () % 1000 < iPercent)
  1432.         {
  1433.           ++(*pqbuf)->ab[(*pqbuf)->cend + i];
  1434.           ++c;
  1435.         }
  1436.         }
  1437.       if (zDebug != NULL && c > 0)
  1438.         fprintf (stderr, "Clobbered %d bytes\n", c);
  1439.     }
  1440.  
  1441.       (*pqbuf)->cend += cgot;
  1442.  
  1443.       if (ctotal > 256)
  1444.     return ctotal;
  1445.     }
  1446. }
  1447.  
  1448. /* Write data to a file descriptor until one of the writes gets no
  1449.    data.  */
  1450.  
  1451. static boolean
  1452. fsend (o, oslave, pqbuf)
  1453.      int o;
  1454.      int oslave;
  1455.      struct sbuf **pqbuf;
  1456. {
  1457.   long ctotal;
  1458.  
  1459.   ctotal = 0;
  1460.   while (*pqbuf != NULL)
  1461.     {
  1462.       int cwrite, cwrote;
  1463.  
  1464.       if ((*pqbuf)->cstart >= (*pqbuf)->cend)
  1465.     {
  1466.       struct sbuf *qfree;
  1467.  
  1468.       qfree = *pqbuf;
  1469.       *pqbuf = (*pqbuf)->qnext;
  1470.       free ((pointer) qfree);
  1471.       continue;
  1472.     }
  1473.  
  1474. #ifdef FIONREAD
  1475.       {
  1476.     long cunread;
  1477.  
  1478.     if (ioctl (oslave, FIONREAD, &cunread) < 0)
  1479.       {
  1480.         perror ("FIONREAD");
  1481.         uchild (SIGCHLD);
  1482.       }
  1483.     if (zDebug != NULL)
  1484.       fprintf (stderr, "%ld unread\n", cunread);
  1485.     cwrite = 256 - cunread;
  1486.     if (cwrite <= 0)
  1487.       break;
  1488.       }
  1489. #else /* ! FIONREAD */
  1490.       if (! fwritable (o))
  1491.     break;
  1492.       cwrite = 1;
  1493. #endif /* ! FIONREAD */
  1494.  
  1495.       if (cwrite > (*pqbuf)->cend - (*pqbuf)->cstart)
  1496.     cwrite = (*pqbuf)->cend - (*pqbuf)->cstart;
  1497.  
  1498.       cwrote = write (o, (*pqbuf)->ab + (*pqbuf)->cstart, cwrite);
  1499.       if (cwrote < 0)
  1500.     {
  1501.       if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA)
  1502.         cwrote = 0;
  1503.       else
  1504.         {
  1505.           perror ("write");
  1506.           uchild (SIGCHLD);
  1507.         }
  1508.     }
  1509.       
  1510.       if (cwrote == 0)
  1511.     break;
  1512.  
  1513.       ctotal += cwrote;
  1514.       (*pqbuf)->cstart += cwrote;
  1515.     }
  1516.  
  1517.   if (zDebug != NULL && ctotal > 0)
  1518.     fprintf (stderr, "Wrote %ld to %d\n", ctotal, o);
  1519.  
  1520.   return ctotal > 0;
  1521. }
  1522.  
  1523. /* Check whether a file descriptor can be written to.  */
  1524.  
  1525. static boolean
  1526. fwritable (o)
  1527.      int o;
  1528. {
  1529. #if HAVE_SELECT
  1530.  
  1531.   int iwrite;
  1532.   struct timeval stime;
  1533.   int cfds;
  1534.  
  1535.   iwrite = 1 << o;
  1536.  
  1537.   stime.tv_sec = 0;
  1538.   stime.tv_usec = 0;
  1539.  
  1540.   cfds = select (o + 1, (pointer) NULL, (pointer) &iwrite,
  1541.          (pointer) NULL, &stime);
  1542.   if (cfds < 0)
  1543.     {
  1544.       perror ("select");
  1545.       uchild (SIGCHLD);
  1546.     }
  1547.  
  1548.   return cfds > 0;
  1549.  
  1550. #else /* ! HAVE_SELECT */
  1551.  
  1552. #if HAVE_POLL
  1553.  
  1554.   struct pollfd s;
  1555.   int cfds;
  1556.  
  1557.   s.fd = o;
  1558.   s.events = POLLOUT;
  1559.  
  1560.   cfds = poll (&s, 1, 0);
  1561.   if (cfds < 0)
  1562.     {
  1563.       perror ("poll");
  1564.       uchild (SIGCHLD);
  1565.     }
  1566.  
  1567.   return cfds > 0;
  1568.  
  1569. #endif /* HAVE_POLL */
  1570. #endif /* ! HAVE_SELECT */
  1571. }
  1572.  
  1573. /* A version of the system command that checks for errors.  */
  1574.  
  1575. static void
  1576. xsystem (zcmd)
  1577.      const char *zcmd;
  1578. {
  1579.   int istat;
  1580.  
  1581.   istat = system ((char *) zcmd);
  1582.   if (istat != 0)
  1583.     {
  1584.       fprintf (stderr, "Command failed with status %d\n", istat);
  1585.       fprintf (stderr, "%s\n", zcmd);
  1586.       exit (EXIT_FAILURE);
  1587.     }
  1588. }
  1589.